/**
 * 
 */
package calculation.passed;

/**
 * @author xyyi
 *
 */
public class RomanNumerals {

	// I, IV, 
	public enum Numeral {
		I(1), IV(4), V(5), IX(9), X(10), XL(40), L(50), XC(90), C(100), CD(400), D(
				500), CM(900), M(1000);

		int weight;

		Numeral(int weight) {
			this.weight = weight;
		}
	}

	public enum RomaNumber {
		I(1), IV(4), V(5), IX(9), X(10), XL(40), L(50), XC(90), C(100), CD(400), D(
				500), CM(900), M(1000);

		private int value;

		RomaNumber(int value) {
			this.value = value;
		}
		
		public int getValue() {
			return value;
		}

	}

	/**
	Given an integer, convert it to a roman numeral.

	Input is guaranteed to be within the range from 1 to 3999.
	 */
	public String intToRoman(int num) {
		RomaNumber[] romaNumbers = RomaNumber.values();
		StringBuffer sb = new StringBuffer();
		for (int i = romaNumbers.length - 1; i >= 0; i--) {
			while (num >= romaNumbers[i].getValue()) {
				sb.append(romaNumbers[i].name());
				num -= romaNumbers[i].getValue();
			}
		}

		return sb.toString();
	}

	/**
	 Given a roman numeral, convert it to an integer.

	Input is guaranteed to be within the range from 1 to 3999.
	 */
	public int romanToInt(String s) {
		if (s == null || s.isEmpty())
			return 0;
		RomaNumber[] romaNumbers = RomaNumber.values();
		int result = 0;
		for (int i = romaNumbers.length - 1, si = 0; i >= 0; i--) {
			while (s.indexOf(romaNumbers[i].name(), si) == si) {
				result += romaNumbers[i].value;
				si += romaNumbers[i].name().length();
			}
		}

		return result;
	}

	public static String toRoman(long n) {
		if (n <= 0) {
			throw new IllegalArgumentException();
		}

		Numeral[] values = Numeral.values();
		long current = n;
		StringBuffer sb = new StringBuffer();
		for (int i = values.length - 1; i >= 0; i--) {
			while (values[i].weight <= current) {
				current = current - values[i].weight;
				sb.append(values[i].name());
			}
		}

		return sb.toString();
	}

	public static String roman(long n) {
		if (n <= 0) {
			throw new IllegalArgumentException();
		}
		StringBuilder buf = new StringBuilder();

		final Numeral[] values = Numeral.values();
		for (int i = values.length - 1; i >= 0; i--) {
			while (n >= values[i].weight) {
				buf.append(values[i]);
				n -= values[i].weight;
			}
		}
		return buf.toString();
	}

	public static int toNumber(String roman) {
		int result = 0;
		//StringBuffer current = new StringBuffer(roman);
		String current = roman;
		final Numeral[] values = Numeral.values();
		for (int i = values.length - 1, currIdx = 0; i >= 0; i--) {
			while (current.indexOf(values[i].name(), currIdx) == currIdx) {
				result = result + values[i].weight;
				currIdx = currIdx + values[i].name().length();
			}
		}

		return result;
	}

	public static void testToRoman(long n) {
		System.out.println(n + " = " + toRoman(n));
	}

	public static void testToNumber(String roman) {
		System.out.println(roman + " = " + toNumber(roman));
	}

	/**
	class Solution {
		public:
		    int romanToInt(string s) {
		        // Start typing your C/C++ solution below
		        // DO NOT write int main() function
		    int lk_tbl[26];
		    int idx;
		    int sum;
		    int cur = 0, prev = 0;
		int size=s.length();
		    memset(lk_tbl, 0, sizeof(lk_tbl));
		    lk_tbl['I'-'A'] = 1;
		    lk_tbl['V'-'A'] = 5;
		    lk_tbl['X'-'A'] = 10;
		    lk_tbl['L'-'A'] = 50;
		    lk_tbl['C'-'A'] = 100;
		    lk_tbl['D'-'A'] = 500;
		    lk_tbl['M'-'A'] = 1000;
		    sum = 0;
		    for (idx = size - 1; idx >= 0; idx--) {
		        prev = cur;
		        cur = lk_tbl[s[idx]-'A'];
		        if (cur >＝ prev) {
		            sum += cur;
		        } else {
		            sum -= cur;
		        }
		    }
		    
		    return sum;
		 }
	*/
	/**
	void
	toRoman1(int num)
	{
	   char* tbl10[] = {"", "I", "II", "III", "IV", "V", "VI" "VII", "VIII", "IX"};
	   char* tbl100[] = {"", "X", "XX", "XXX", "XL", "LX", "LXX", "LXXX", "XC"};
	   char* tbl1000[] = {"", "C", "CC", "CCC", "CD", "DC", "DCC", "DCCC", "CM"};
	   char* tbl10000[] = {"", "M", "MM", "MMM"};

	   if (num > 4000 || num < 0)
	     return;
	   if (num / 1000)
	       printf("%s", tbl10000[num/1000]);
	   num %= 1000;

	   if (num / 100)
	       printf("%s", tbl1000[num/100]);
	   num %= 100;

	   if (num / 10)
	       printf("%s", tbl100[num/10]);
	   num %= 10;

	   printf("%s", tbl100[num]);

	}
	*/
	/**
	 * 
	 */
	public RomanNumerals() {
		// TODO Auto-generated constructor stub
	}

	/**
	 * @param args
	 */
	public static void main(String[] args) {
		String[] romans = { "I", "II", "III", "IV", "V", "VI", "VII", "VIII",
				"IX", "X", "MCMXCIX", "XXV", "CMXLIV" };
		for (int i = 0; i < romans.length; i++) {
			testToNumber(romans[i]);
		}

		for (int i = 1; i <= 20; i++) {
			testToRoman(i);
		}
		testToRoman(1999);
		testToRoman(25);
		testToRoman(944);
		//test(0);
	}

}
